﻿using MongoDB.Bson;
using MongoDB.Driver;
using MongoDB.Driver.GridFS;
using Sustainalytics.Download.Entities;
using Sustainalytics.MongoDB.Extensions;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Sustainalytics.Download.GridFs
{
    public class DownloadFromGridFs
    {
        private GridFSBucket bucket;
        private IMongoCollection<PIInputFile> _inputFileCollection;

        public DownloadFromGridFs(
            IMongoDatabase database,
            IMongoCollection<PIInputFile> inputFileCollection)
        {
            bucket = new GridFSBucket(database);
            _inputFileCollection = inputFileCollection;
        }

        public async Task<IEnumerable<GridFsFile>> GetFilesList(int page = 0, int take = 10, bool getProductInvolvementFilesOnly = false)
        {
            var results = await bucket
                .Find(GetFilters(getProductInvolvementFilesOnly),
                    new GridFSFindOptions
                    {
                        Limit = take,
                        Sort = Builders<GridFSFileInfo>.Sort.Descending(x => x.UploadDateTime),
                        Skip = (page - 1) * take
                    })
                .ToListAsync()
                .ConfigureAwait(false);

            return results.Select(x => new GridFsFile()
            {
                Id = x.Id,
                Name = x.Filename,
                UploadDate = x.UploadDateTime,
                Extension = x.Filename.Split('.').LastOrDefault(),
                Metadata = x.Metadata
            });
        }

        public async Task<int> GetFilesCount(bool getProductInvolvementFilesOnly = false)
        {
            var results = await bucket
                .Find(GetFilters(getProductInvolvementFilesOnly), null)
                .ToListAsync()
                .ConfigureAwait(false);

            return results.Count;
        }
        private FilterDefinition<GridFSFileInfo> GetFilters(bool getProductInvolvementFilesOnly)
        {
            if (!getProductInvolvementFilesOnly)
                return Builders<GridFSFileInfo>.Filter.Empty;

            var inputFiles = _inputFileCollection
                .Find(_ => true)
                .Project(x => x.Id)
                .ToList();

            return Builders<GridFSFileInfo>.Filter.In("Metadata._id", inputFiles);
        }

        public async Task<GridFsFile> GetFile(ObjectId param)
        {
            var result = await bucket
                .Find(
                    Builders<GridFSFileInfo>.Filter.Eq("_id", param),
                    null)
                .FirstOrDefaultAsync()
                .ConfigureAwait(false);

            return new GridFsFile()
            {
                Id = result.Id,
                Name = result.Filename,
                UploadDate = result.UploadDateTime,
                Extension = result.Filename.Split('.').LastOrDefault(),
                Metadata = result.Metadata
            };
        }

        public async Task<byte[]> GetFileContent(ObjectId param)
        {
            var bsonValue = BsonValue.Create(param);

            return await bucket.DownloadAsBytesAsync(bsonValue).ConfigureAwait(false);
        }
    }
}
